use cmsis_rtos2_rs::static_mem::MutexValue;

use super::super::driver::{ctrl, APP_INFO};
pub use crate::conn::weight::status;
use crate::cp_heat::Error;

#[derive(Clone, Copy, PartialEq, Eq)]
enum Bucket {
    B1,
    B2,
}

pub enum CtrlType {
    V7,
    V6,
    V5,
}

struct DrawStatus {
    v7_flag: bool,
    v6_flag: bool,
    v5_flag: bool,
}

static DRAW_STATUS: MutexValue<DrawStatus> = MutexValue::uninit(DrawStatus {
    v5_flag: false,
    v6_flag: false,
    v7_flag: false,
});

impl Bucket {}

impl DrawStatus {
    pub fn ctrl(&mut self, ty: CtrlType, flag: bool) -> Result<(), Error> {
        match ty {
            CtrlType::V5 => self.v5_flag = flag,
            CtrlType::V6 => self.v6_flag = flag,
            CtrlType::V7 => self.v7_flag = flag,
        }
        self.exec()
    }

    fn exec(&self) -> Result<(), Error> {


        if self.v6_flag {
            ctrl::v6_open();
        } else {
            ctrl::v6_close();
        }

        if self.v7_flag {
            ctrl::v7_open();
        } else {
            ctrl::v7_close();
        }

        if self.v5_flag || self.v6_flag || self.v7_flag {
            let bucket = self.select_bucket()?;
            self.open(bucket);
        } else {
            self.close_all();
        }
        
        Ok(())
    }

    fn close_all(&self) {
        ctrl::bucket1_pump_close();
        ctrl::bucket2_pump_close();
    }

    fn open(&self, bucket: Bucket) {
        match bucket {
            Bucket::B1 => {
                ctrl::bucket1_pump_open();
                ctrl::bucket2_pump_close();
            }
            Bucket::B2 => {
                ctrl::bucket1_pump_close();
                ctrl::bucket2_pump_open();
            }
        }
    }

    fn select_bucket(&self) -> Result<Bucket, Error> {
        let min = APP_INFO.lock().min_draw_weight;
        let state = status()?;
        if (state.bucket1 < min) && (state.bucket2 < min) {
            self.close_all();
            return Err(Error::BucketIsEmpty);
        }

        if state.bucket1 < state.bucket2 {
            if state.bucket1 > min {
                Ok(Bucket::B1)
            } else {
                Ok(Bucket::B2)
            }
        } else {
            if state.bucket2 > min {
                Ok(Bucket::B2)
            } else {
                Ok(Bucket::B1)
            }
        }
    }
}

pub unsafe fn init() {
    DRAW_STATUS.init_once("draw");
}

pub fn ctrl(ty: CtrlType, flag: bool) -> Result<(), Error> {
    DRAW_STATUS.lock().ctrl(ty, flag)
}

pub fn is_bucket_enough() -> Result<bool, Error> {
    let status = status()?;
    let min = APP_INFO.lock().min_draw_weight;
    Ok((status.bucket1 >= min) || (status.bucket2 >= min))
}
